home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_UMINNgopher.idb / usr / freeware / src / gopher_1.12 / gopher / gopher.c.z / gopher.c
C/C++ Source or Header  |  1997-09-09  |  34KB  |  1,466 lines

  1. /********************************************************************
  2.  * $Author: drich $
  3.  * $Revision: 1.1 $
  4.  * $Date: 1995/10/03 04:08:04 $
  5.  * $Source: /proj/freeware1.0/gopher1.12/src/gopher/RCS/gopher.c,v $
  6.  * $State: Exp $
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: gopher.c
  14.  * Main functions for the gopher client
  15.  *********************************************************************
  16.  * Revision History:
  17.  * $Log: gopher.c,v $
  18.  * Revision 1.1  1995/10/03  04:08:04  drich
  19.  * gopher 1.2 check-in
  20.  *
  21.  * Revision 1.15  1993/01/17  03:46:46  lindner
  22.  * Fixes for tmpname memory leak.
  23.  *
  24.  * Revision 1.14  1993/01/15  20:14:27  lindner
  25.  * Added -T to the usage line
  26.  *
  27.  * Revision 1.13  1993/01/14  22:00:21  lindner
  28.  * added ^R and ^W to redraw the screen for VMS
  29.  * Old search terms don't persist now when highlighting text.
  30.  *
  31.  * Revision 1.12  1993/01/13  16:18:11  lindner
  32.  * Put back in 's' save patch...  Sigh...
  33.  *
  34.  * Revision 1.11  1993/01/12  22:38:56  lindner
  35.  * Rescinded changes for sound on VMS, it doesn't work!
  36.  *
  37.  * Revision 1.10  1993/01/12  21:42:14  lindner
  38.  * Fixed problem with viewing files in secure mode.
  39.  * Fixed problems with suck_sound in VMS.
  40.  * Fixed problems with \n on the system command in VMS
  41.  *
  42.  * Revision 1.9  1993/01/12  17:30:17  lindner
  43.  * Fixed problem with 's' key for save_file.
  44.  *
  45.  * Revision 1.8  1993/01/09  02:33:46  lindner
  46.  * Fixed definitions for controlc() and sizechange()
  47.  *
  48.  * Revision 1.7  1993/01/09  02:18:40  lindner
  49.  * Changed (void*)-1 constructs to SIG_ERR
  50.  *
  51.  * Revision 1.6  1993/01/08  19:25:02  lindner
  52.  * Securemode users can't display graphics now, they get a message instead..
  53.  *
  54.  * Revision 1.5  1993/01/07  22:49:40  lindner
  55.  * Added option -T to set initial type.  Added 'D' command for downloading
  56.  *
  57.  * Revision 1.4  1992/12/31  06:34:49  lindner
  58.  * Okay, okay, Save_File is really Save_file
  59.  *
  60.  * Revision 1.3  1992/12/31  05:38:01  lindner
  61.  * Removed getfile() replaced with Save_File().
  62.  *
  63.  * Revision 1.2  1992/12/31  04:34:38  lindner
  64.  * Added VMS support from fogel and jqj.
  65.  *
  66.  * Revision 1.1  1992/12/10  23:32:16  lindner
  67.  * gopher 1.1 release
  68.  *
  69.  *********************************************************************/
  70.  
  71.  
  72. #include "gopher.h"
  73.  
  74. void describe_gopher();
  75.  
  76. /*
  77. ** Open a connection to another host using telnet or tn3270
  78. */
  79.  
  80. void
  81. do_tel_3270(ZeGopher)
  82.   GopherStruct *ZeGopher;
  83. {
  84.      char *Dialogmess[20];
  85.  
  86.      char sMessage1[128];
  87.      char sMessage2[128];
  88.      char sTelCmd[128]; 
  89.  
  90.      /* retrieve the gopher information for the telnet command*/
  91.  
  92.      clear();
  93.      Dialogmess[0] = "Warning!!!!!, you are about to leave the Internet";
  94.      Dialogmess[1] = "Gopher program and connect to another host. If";
  95.      Dialogmess[2] = "you get stuck press the control key and the ] key,";
  96.      Dialogmess[3] = "and then type quit";
  97.      Dialogmess[4] = "";
  98.      
  99.      if (GSgetPort(ZeGopher) != 0)
  100.       sprintf(sMessage1,"Connecting to %s, port %d using %s.", GSgetHost(ZeGopher),GSgetPort(ZeGopher), (GSgetType(ZeGopher) == A_TN3270) ? "tn3270" : "telnet");
  101.      else
  102.       sprintf(sMessage1, "Connecting to %s using %s.", GSgetHost(ZeGopher),(GSgetType(ZeGopher) == A_TN3270) ? "tn3270" : "telnet");
  103.  
  104.      Dialogmess[5] = sMessage1;
  105.  
  106.      if (*GSgetPath(ZeGopher) != '\0')
  107.       sprintf(sMessage2,"Use the account name \"%s\" to log in",
  108.           GSgetPath(ZeGopher));
  109.      else
  110.       sMessage2[0] = '\0';
  111.  
  112.      Dialogmess[6] = "";
  113.      Dialogmess[7] = sMessage2;
  114.      Dialogmess[8] = NULL;
  115.  
  116.      if (CURDialog(CursesScreen, GSgetTitle(ZeGopher), Dialogmess) <0)
  117.       return;
  118.  
  119.      CURexit(CursesScreen);
  120.  
  121.      if (GSgetType(ZeGopher) == 'T') {
  122.       /**** A TN3270 connection ****/
  123.       sprintf(sTelCmd, "%s %s", STRget(TN3270Command),
  124.           GSgetHost(ZeGopher));
  125.      } else
  126.  
  127.       if (GSgetPort(ZeGopher) != 0 && GSgetPort(ZeGopher) != 23) 
  128. #if defined(VMS) && defined(MULTINET)
  129.                sprintf(sTelCmd, "%s %s /PORT=%d",
  130. #else
  131.            sprintf(sTelCmd, "%s %s %d",
  132. #endif
  133.                STRget(TelnetCommand), GSgetHost(ZeGopher),
  134.                GSgetPort(ZeGopher)); 
  135.       else 
  136.            sprintf(sTelCmd, "%s %s", STRget(TelnetCommand), 
  137.                GSgetHost(ZeGopher));
  138.      
  139.      CURexit(CursesScreen);
  140.      system(sTelCmd);
  141.      CURenter(CursesScreen);
  142.      return;
  143. }
  144.  
  145.  
  146.  
  147.  
  148.  
  149. /*
  150. ** do_index gets keywords from the user to search for.  It returns
  151. ** it to the calling process.  This storage is volotile. Callers should
  152. ** make a copy if they want to call do_index multiple times.
  153. */
  154.  
  155. char* do_index(ZeGopher)
  156.   GopherStruct *ZeGopher;
  157. {
  158.      static char *inputline = NULL;
  159.      static char *prompt[2];
  160.      static char *response[2];
  161.  
  162.      if (inputline == NULL) {
  163.       inputline = (char *) malloc(sizeof(char)*256);
  164.       if (inputline == NULL)
  165.            perror("Out of memory"), exit(-1);
  166.       *inputline = '\0';
  167.      }
  168.  
  169.      prompt[0] = "Words to search for";
  170.      prompt[1] = NULL;
  171.  
  172.      response[0] = inputline;
  173.      response[1] = NULL;
  174.  
  175.      if (CURRequest(CursesScreen, GSgetTitle(ZeGopher),prompt, response) == -1 )
  176.       return(NULL);
  177.  
  178.      if (*inputline == '\0')
  179.       return(NULL);
  180.      else
  181.       return(inputline);
  182. }
  183.  
  184.  
  185. /*
  186.  * this procedure just retrieves binary data from the socket and
  187.  * pumps it into a "play" process.
  188.  */
  189.  
  190. #define BUFSIZE 1400  /* A pretty good value for ethernet */
  191.  
  192. #ifndef VMS
  193. void
  194. suck_sound(sockfd)
  195.   int sockfd;
  196. {
  197.      FILE *Play;
  198.      int j;
  199.      char buf[BUFSIZE];
  200.  
  201.      if (*STRget(PlayCommand) == '\0') {
  202.       /*** Hey! no play command, bummer ***/
  203.       CursesErrorMsg("Sorry, this machine doesn't support sounds");
  204.  
  205.       return;
  206.      }
  207.  
  208.      Play = popen(STRget(PlayCommand), "w");
  209.       
  210.      
  211.      while(1) {
  212.           j = read(sockfd, buf, BUFSIZE);
  213.       
  214.       if (j == 0)
  215.            break;
  216.       
  217.       fwrite(buf, 1, j, Play);
  218.      }
  219. }
  220. #endif
  221.  
  222. /*
  223.  * fork off a sound process to siphon the data across the net.
  224.  * So the user can listen to tunage while browsing the directories.
  225.  */
  226.  
  227. void
  228. do_sound(ZeGopher)
  229.   GopherStruct *ZeGopher;
  230. {
  231. #ifdef VMS
  232.      CursesErrorMsg("Sorry, this machine doesn't support sounds");
  233. #else
  234.      int sockfd;
  235.      char sTmp[5];
  236.      BOOLEAN Waitforchld = FALSE;
  237.  
  238.      sTmp[0] = '\0';
  239.  
  240.      if ((sockfd = GSconnect(ZeGopher)) <0) {
  241.       check_sock(sockfd, GSgetHost(ZeGopher), GSgetPort(ZeGopher));
  242.       return;
  243.      }
  244.  
  245.      /** Send out the request **/
  246.  
  247.      writestring(sockfd, GSgetPath(ZeGopher));
  248.      writestring(sockfd, "\r\n");
  249.  
  250.      /** Okay, it's cool, we can fork off **/
  251.  
  252.      if (SOUNDCHILD != 0)
  253.       Waitforchld = TRUE;
  254.  
  255.  
  256.      if ( (SOUNDCHILD = fork()) < 0)
  257.       ;/* Fork Error */
  258.      
  259.      else if (SOUNDCHILD == 0) {  /* Child Process */
  260.       wait(SIGCHLD);
  261.       suck_sound(sockfd);
  262.       exit(0);
  263.      }
  264.      
  265.      /* Parent Process */
  266.      
  267.      closenet(sockfd);
  268.      return;
  269. #endif  /* not VMS */
  270. }
  271.  
  272.  
  273.  
  274. /*
  275.  * Replace the searched words with backspaces and underline characters.
  276.  */
  277.  
  278. static char sGBoldoutput[20];  /*** Used for stripping weird stuff from
  279.                     term strings ***/
  280. static int iGposition = 0;     /*** Pointer into the Boldoutput string **/
  281.  
  282. /*** Used by tputs() ***/
  283.  
  284. int
  285. Boldoutchar(c)
  286.   char c;
  287. {
  288.      sGBoldoutput[iGposition++] = c;
  289.      return(c);
  290. }
  291.  
  292.  
  293. void
  294. Boldit(inputline, outputline, MungeSearchstr)
  295.   char *inputline, *outputline, *MungeSearchstr;
  296. {
  297.      char words[20][40];  /** A reasonable guess **/
  298.      int numchars, lowwordnum, wordcount, i;
  299.      char *cp, *lowword;
  300.  
  301.      outputline[0] = '\0';
  302.  
  303.      bzero(outputline, 512);
  304.      
  305.      while (isspace(*MungeSearchstr)) /** Strip off spaces **/
  306.       MungeSearchstr++;
  307.       
  308.      for (wordcount=0; wordcount<20; wordcount++) {
  309.  
  310.       while (isspace(*MungeSearchstr)) /** Strip off spaces **/
  311.            MungeSearchstr++;
  312.       
  313.       numchars = sreadword(MungeSearchstr, words[wordcount], 40);
  314.       MungeSearchstr += numchars;
  315.       if (numchars == 0)
  316.            break;
  317.       if (strcmp(words[wordcount], "and")==0 ||
  318.           strcmp(words[wordcount], "or")==0 ||
  319.           strcmp(words[wordcount], "not")==0) {
  320.            words[wordcount][0] = '\0';
  321.            wordcount--;
  322.       }
  323.      }
  324.  
  325.  
  326.      /** Find the first word in the line **/
  327.  
  328.      while (*inputline!='\0') {
  329.       lowword = NULL;
  330.  
  331.       for (i=0; i< wordcount; i++) {
  332.            cp = strcasestr(inputline, words[i]);
  333.            if (cp != NULL)
  334.             if (cp < lowword || lowword == NULL) {
  335.              lowword = cp;
  336.              lowwordnum = i;
  337.             }
  338.       }
  339.  
  340.       if (lowword == NULL) {
  341.            strcpy(outputline, inputline);
  342.            return;
  343.       }
  344.       else {
  345.            strncpy(outputline, inputline, lowword - inputline);
  346.            outputline += (lowword - inputline);
  347.            inputline = lowword;
  348.            
  349.            iGposition = 0;
  350.            tputs(CURgetHighon(CursesScreen), 1, Boldoutchar);
  351.            sGBoldoutput[iGposition] = '\0';
  352.            strcpy(outputline, sGBoldoutput);
  353.            outputline += strlen(sGBoldoutput);
  354.  
  355.            strncpy(outputline, inputline, strlen(words[lowwordnum]));
  356.            inputline += strlen(words[lowwordnum]);
  357.            outputline += strlen(words[lowwordnum]);
  358.  
  359.  
  360.            iGposition = 0;
  361.            tputs(CURgetHighoff(CursesScreen), 1, Boldoutchar);
  362.            sGBoldoutput[iGposition] = '\0';
  363.            strcpy(outputline, sGBoldoutput);
  364.            outputline += strlen(sGBoldoutput);
  365.  
  366.       }
  367.      }
  368. }
  369.  
  370.  
  371. /**
  372. *** Show file takes a gopher text thing, writes it to a file
  373. *** and passes it to your favorite pager.
  374. **/
  375.  
  376. void
  377. showfile(ZeGopher)
  378.   GopherStruct *ZeGopher;
  379. {
  380.      int i=0, iLength, sockfd;
  381.      char *tmpfilename;
  382.      FILE *tmpfile;
  383.      char inputline[512];
  384.      char outputline[512];
  385.      char sTmp[5];
  386.      int twirlcounter=0;
  387.  
  388.      sTmp[0] = '\0';
  389.  
  390.      /** Open a temporary file **/
  391.  
  392.      Gopenfile = tmpfilename = tempnam("/tmp","gopher");
  393.  
  394.      if ((tmpfile = fopen(tmpfilename, "w")) == NULL)
  395.       fprintf(stderr, "Couldn't make a tmp file!\n"), exit(-1);
  396.  
  397.  
  398.      /** Send out the request **/
  399.  
  400.      if ((sockfd = GSconnect(ZeGopher)) <0) {
  401.       check_sock(sockfd, GSgetHost(ZeGopher), GSgetPort(ZeGopher));
  402.       return;
  403.      }
  404.  
  405.      writestring(sockfd, GSgetPath(ZeGopher));
  406.      writestring(sockfd, "\r\n");
  407.  
  408.      /*** Case here on the object type,  Get it line-by-line for text,
  409.           binary mode if it's supported. ***/
  410.  
  411.      if (GSgetType(ZeGopher) == A_IMAGE || GSgetType(ZeGopher) == A_GIF) {
  412.       char buf[BUFSIZE]; int cc = 0;
  413.       int counter = 0;
  414.  
  415.       while ( (cc = readn( sockfd, buf, BUFSIZE )) > 0 ) {
  416.            counter += cc;
  417.            
  418.            if (write(fileno(tmpfile), buf, cc ) <=0)
  419.             CursesErrorMsg("Problems Writing File");
  420.            twirl();
  421.       }
  422.       if ( cc < 0 )
  423.            CursesErrorMsg( "Warning! File may be corrupt!");
  424.       else {
  425.            CursesErrorMsg( "File received successfully" );
  426.       }
  427.       fclose( tmpfile );
  428.      } else {
  429.       while (1) {
  430.            /** make a mark for every page **/
  431.            twirlcounter++;
  432.            
  433.            if ((twirlcounter % 25) == 0)
  434.             twirl();
  435.            
  436.            iLength = readline(sockfd, inputline, 512);
  437.            outputline[0] = '\0';
  438.            if (iLength == 0)
  439.             break;
  440.            
  441.            ZapCRLF(inputline);
  442.            
  443.            
  444.            /*** Ugly hack ahead..... ***/
  445.            
  446.            if (GSgetType(ZeGopher) == A_CSO) {
  447.             if (inputline[0] == '2')
  448.              break;
  449.             
  450.             if ((inputline[0] >= '3') && (inputline[0] <= '9'))  {
  451.              fprintf(tmpfile, "%s\n", GSgetPath(ZeGopher));
  452.              fprintf(tmpfile, "%s\n", inputline+4);
  453.              break;
  454.             }
  455.             if (inputline[0] == '-') {
  456.  
  457.  
  458.              if (inputline[1] >= '3' && inputline[1] <= '9') {
  459.                   fprintf(tmpfile, "%s\n", GSgetPath(ZeGopher));
  460.                   fprintf(tmpfile, "%s\n", inputline+5);
  461.              }
  462.              else {
  463.                   char *colonpos = strchr(inputline+5,':');
  464.                              if (colonpos != NULL && *(colonpos-1) != i) {
  465.                                   fprintf(tmpfile, "-------------------------------------------------------\n");
  466.                                   i = *(colonpos-1);
  467.                                   }
  468.                              fputs((colonpos ? colonpos+1 : inputline+6), tmpfile);
  469.                              fputc('\n', tmpfile);
  470.              }
  471.             }
  472.            }
  473.            
  474.            if (GSgetType(ZeGopher) == A_FILE) {
  475.             if ((inputline[0] == '.') && (inputline[1] == '\0'))
  476.              break;
  477.             else {
  478.              /*** Underline searched words, except and, or and not ***/
  479.              if (Searchstring != NULL) {
  480.                   Boldit(inputline, outputline, Searchstring);
  481.              }
  482.              else
  483.                   strcpy(outputline, inputline);
  484.              fputs(outputline, tmpfile);
  485.              fputc('\n', tmpfile);
  486.             }
  487.            }
  488.            else if (GSgetType(ZeGopher) == A_MIME) {
  489.             if ((inputline[0] == '.') && (inputline[1] == '\0'))
  490.              break;
  491.             else {
  492.              fputs(inputline, tmpfile);
  493.              fputc('\n', tmpfile);
  494.             }
  495.            }
  496.       }
  497.  
  498.       /** Work around a bug in xterm n' curses*/      
  499.       fprintf(tmpfile, "\012 \n\n");  
  500.       (void)fclose(tmpfile);
  501.      }
  502.      closenet(sockfd);
  503.  
  504.      if (GSgetType(ZeGopher) == A_MIME)
  505.       display_mime(tmpfilename, GSgetTitle(ZeGopher));
  506.      else if (GSgetType(ZeGopher) == A_IMAGE || GSgetType(ZeGopher)== A_GIF)
  507.       display_image(tmpfilename, GSgetTitle(ZeGopher));
  508.      else
  509.       display_file(tmpfilename, ZeGopher);
  510.  
  511.      /** Good little clients clean up after themselves..**/
  512.  
  513.      if (unlink(tmpfilename)!=0)
  514.       fprintf(stderr, "Couldn't unlink!!!\n"), exit(-1);
  515.  
  516.      Gopenfile = NULL;
  517.      free(tmpfilename);
  518.      CURenter(CursesScreen);
  519.  
  520.      return;
  521. }
  522.  
  523.  
  524. /*
  525. ** Pushgopher takes a GopherThing pointer and adds it to it's stack.
  526. **
  527. ** Ick this must be fixed!
  528. */
  529.  
  530. void
  531. pushgopher(ZeDir)
  532.   GopherDirObj *ZeDir;
  533. {
  534.  
  535.      OldDirs[iLevel]= ZeDir;
  536.      iLevel ++;
  537. }
  538.  
  539. /*
  540. ** If the stack is empty, popgopher returns a -1
  541. */
  542.  
  543. int
  544. popgopher(ZeDir)
  545.   GopherDirObj **ZeDir;
  546. {
  547.  
  548.      if (iLevel == 0)
  549.       return(-1);
  550.  
  551.      iLevel --;
  552.  
  553.      *ZeDir =  OldDirs[iLevel];
  554.  
  555.      return(0);
  556. }
  557.  
  558.  
  559. void check_sock(sockfd, host, port)
  560.   int sockfd;
  561.   char *host;
  562.   int port;
  563. {
  564.      char DispString[WHOLELINE];
  565.      char *DispStrings[4];
  566.  
  567.      if (sockfd <0) {
  568.       sprintf(DispString, "Cannot connect to host %s, port %d.", host, port);
  569.       switch (sockfd) {
  570.       case -2:
  571.            DispStrings[2] = "Hostname is unknown.";
  572.            break;
  573.       case -3:
  574.            DispStrings[2] = "Unable to allocate a socket.";
  575.            break;
  576.       case -4:
  577.            DispStrings[2] = "Connection refused by host.";
  578.            break;
  579.       default:
  580.            DispStrings[2] = "Unknown error.";
  581.       }
  582.       DispStrings[0] = DispString;
  583.       DispStrings[1] = "";
  584.       DispStrings[3] = NULL;
  585.  
  586.       CURDialog(CursesScreen, "Network Error", DispStrings);
  587.      }
  588. }
  589.  
  590.  
  591. BOOLEAN
  592. ReallyQuit()
  593. {
  594.      char yesno[3];
  595.            
  596.      yesno[0] = 'y';
  597.      yesno[1] = '\0';
  598.      
  599.      CURgetYesorNo(CursesScreen, "Really quit (y/n) ?", yesno);
  600.      if (*yesno == 'y') {
  601.       return(TRUE);
  602.      }
  603.      
  604.      return(FALSE);
  605. }
  606.      
  607.  
  608. /***************
  609. ** Abort() catches sigpipes and other unknown signals
  610. */
  611. void
  612. Abort(sig)
  613.   int sig;
  614. {
  615.      if (Gopenfile != NULL)
  616.       unlink(Gopenfile);
  617.      exit(-1);
  618. }
  619.  
  620.  
  621. /**************
  622. ** This bit of code catches control-c's, it cleans up the curses stuff.
  623. */
  624. void
  625. controlc(sig)
  626.   int sig;
  627. {
  628.  
  629.      if (Gopenfile != NULL) 
  630.       if (unlink(Gopenfile) < 0)
  631.            if (errno != ENOENT)
  632.             fprintf(stderr, "could not unlink %s\n", Gopenfile);
  633.      
  634. #ifdef VMS
  635.      if (1)
  636. #else
  637.      if (ReallyQuit())
  638. #endif
  639.      {
  640.       CURexit(CursesScreen);
  641.       if (ChangedDefs)
  642.            write_rc();
  643.       exit(0);
  644.      }
  645.      else {
  646.       CURresize(CursesScreen);
  647.       scline(-1, 1, CurrentDir);
  648.       /** Interrupt search, go back a level?? **/
  649.      }
  650.  
  651.      /*
  652.       * Reprime the signals...
  653.       */
  654.  
  655.      if (signal(SIGINT, controlc) == SIG_ERR)
  656.       perror("signal died:\n"), exit(-1);
  657.        
  658. }
  659.  
  660.  
  661. /**************
  662. ** This bit of code catches window size change signals
  663. **/
  664.  
  665. void
  666. sizechange(sig)
  667.   int sig;
  668. {
  669.      int lines, cols;
  670.      
  671. #ifdef  TIOCGWINSZ
  672.      static struct      winsize zewinsize;        /* 4.3 BSD window sizing */
  673. #endif
  674.  
  675.      lines = LINES;
  676.      cols  = COLS;
  677.      
  678. #ifdef  TIOCGWINSZ
  679.      if (ioctl(0, TIOCGWINSZ, (char *) &zewinsize) == 0) {
  680.       lines = zewinsize.ws_row;
  681.       cols  = zewinsize.ws_col;
  682.      } else {
  683. #endif
  684.       /* code here to use sizes from termcap/terminfo, not yet... */
  685.       ;
  686. #ifdef  TIOCGWINSZ
  687.      }
  688.  
  689.      if (lines != LINES || cols != COLS) {
  690.       LINES = lines;
  691.       COLS  = cols;
  692.       CURresize(CursesScreen);
  693.      
  694.       scline(-1, 1, CurrentDir);
  695.      }
  696.  
  697.      if (signal(SIGWINCH, sizechange)==SIG_ERR)
  698.       perror("signal died:\n"), exit(-1);
  699.  
  700.         
  701. #endif
  702.  
  703. }
  704.  
  705.  
  706.  
  707. /**********
  708. **
  709. ** Set up all the global variables.
  710. **
  711. ***********/
  712.  
  713. void
  714. Initialize()
  715. {
  716.  
  717.      PagerCommand    = STRnew();
  718.      PrinterCommand  = STRnew();
  719.      TelnetCommand   = STRnew();
  720.      TN3270Command   = STRnew();
  721.      PlayCommand     = STRnew();
  722.      MailCommand     = STRnew();
  723.      EditorCommand   = STRnew();
  724.      MIMECommand     = STRnew();
  725.      ImageCommand    = STRnew();
  726.  
  727.      /** get defaults from the rc file **/
  728.  
  729.      set_defs();
  730.      read_rc();
  731.      read_env();
  732.  
  733.  
  734.      /*** Set up the curses environment ***/
  735.      
  736.      CursesScreen = CURnew();
  737.  
  738.      if (strcmp(CURgetTerm(CursesScreen), "unknown")==0)
  739.       fprintf(stderr, "I don't understand your terminal type\n"), exit(-1);
  740.  
  741.  
  742.      /*** Make a signal handler for window size changes ***/
  743.  
  744. #ifdef SIGWINCH
  745.      CURsetSIGWINCH(CursesScreen, sizechange);
  746.      if (signal(SIGWINCH, sizechange)==SIG_ERR)
  747.       perror("signal died:\n"), exit(-1);
  748.  
  749. #endif
  750.  
  751.      if (signal(SIGINT, controlc) == SIG_ERR)
  752.       perror("signal died:\n"), exit(-1);
  753.  
  754.      if (signal(SIGPIPE, Abort) == SIG_ERR)
  755.       perror("signal died:\n"), exit(-1);
  756.  
  757.      /*** Init MainWindow ****/
  758.      CURenter(CursesScreen);
  759. }
  760.  
  761.  
  762. static char *GlobalOptions[] =  
  763. {"Pager Command", "Print Command", "Telnet Command", "Sound Command", "Mail Command", "3270 Emulator Command", "MIME pager", "Image Viewer", NULL};
  764.  
  765.  
  766. void
  767. SetOptions()
  768. {
  769.      static char *Responses[MAXRESP];
  770.      static int inited = FALSE;
  771.  
  772.  
  773.      if (SecureMode) {
  774.       CursesErrorMsg("Sorry, you are not allowed to set options in secure mode.");
  775.       return;
  776.      }
  777.  
  778.  
  779.      if (inited == FALSE) {
  780.       int i; 
  781.  
  782.       for (i=0; i< 8; i++) {
  783.            Responses[i] = (char *) malloc(sizeof(char) * MAXSTR);
  784.       }
  785.       Responses[i] = NULL;
  786.       inited = TRUE;
  787.      }
  788.  
  789.      
  790.      strcpy(Responses[0], STRget(PagerCommand));
  791.      strcpy(Responses[1], STRget(PrinterCommand));
  792.      strcpy(Responses[2], STRget(TelnetCommand));
  793.      strcpy(Responses[3], STRget(PlayCommand));
  794.      strcpy(Responses[4], STRget(MailCommand));
  795.      strcpy(Responses[5], STRget(TN3270Command));
  796.      strcpy(Responses[6], STRget(MIMECommand));
  797.      strcpy(Responses[7], STRget(ImageCommand));
  798.      
  799.      if (CURRequest(CursesScreen, "Options", GlobalOptions, Responses) == 0) {
  800.  
  801.       STRset(PagerCommand, Responses[0]);
  802.       STRset(PrinterCommand, Responses[1]);
  803.       STRset(TelnetCommand, Responses[2]);
  804.       STRset(PlayCommand, Responses[3]);
  805.       STRset(MailCommand, Responses[4]);
  806.       STRset(TN3270Command, Responses[5]);
  807.       STRset(MIMECommand, Responses[6]);
  808.       STRset(ImageCommand, Responses[7]);
  809.       
  810.       ChangedDefs = TRUE;
  811.      }
  812. }
  813.  
  814.  
  815. /* This should be a generalized stack type.  This is icky for now... */
  816.  
  817. int
  818. main(argc, argv)
  819.   int argc;
  820.   char *argv[];
  821. {
  822.      BOOLEAN bDone = FALSE;
  823.      char sTmp[80];
  824.      GopherStruct *RootGophers[2];
  825.      int numhosts = 2;
  826.      int TypedChar;
  827.      /*** for getopt processing ***/
  828.      int c;
  829.      extern char *optarg;
  830.      extern int optind;
  831.      int errflag =0, i;
  832.  
  833.      int Garbled = TRUE;
  834.      boolean Bkmarksfirst = FALSE;
  835.  
  836.      for (i=0; i<2; i++) {
  837.       RootGophers[i] = GSnew();
  838.       GSsetType (RootGophers[i], A_DIRECTORY);   
  839.       GSsetPath (RootGophers[i],"");
  840.      }
  841.      
  842.      /** Should generalize this to >2 hosts .... Sigh... ***/
  843.      GSsetHost (RootGophers[0], CLIENT1_HOST);
  844.      GSsetPort (RootGophers[0], CLIENT1_PORT);
  845.  
  846.      GSsetHost (RootGophers[1], CLIENT2_HOST);
  847.      GSsetPort (RootGophers[1], CLIENT2_PORT);
  848.  
  849.      if (CLIENT2_PORT == 0)
  850.       numhosts = 1;
  851.  
  852.      sTmp[0] = '\0';
  853.  
  854.      while ((c = getopt(argc, argv, "Dsbp:t:T:")) != -1)
  855.       switch (c) {
  856.       case 's':
  857.            SecureMode = TRUE;
  858.            break;
  859.       case 'p':
  860.            GSsetPath(RootGophers[0], optarg);
  861.            GSsetPath(RootGophers[1], optarg);
  862.            break;
  863.       case 'T':
  864.            GSsetType(RootGophers[0], *optarg);
  865.            GSsetType(RootGophers[1], *optarg);
  866.            break;
  867.       case 't':
  868.            GSsetTitle(RootGophers[0], optarg);
  869.            GSsetTitle(RootGophers[1], optarg);
  870.            break;
  871.       case 'D':
  872.            DEBUG = TRUE;
  873.            break;
  874.       case 'b':
  875.            Bkmarksfirst = TRUE;
  876.            break;
  877.       case '?':
  878.            errflag++;
  879.       }
  880.  
  881.  
  882.      if (errflag) {
  883.       fprintf(stderr, "Usage: %s [-sb] [-T type] [-p path] [-t title] [hostname port]+\n", argv[0]);
  884.       exit(-1);
  885.      }
  886.  
  887.      /**** Get host #1 from the command line ****/
  888.      
  889.      if (optind < argc) {
  890.       GSsetHost(RootGophers[0], argv[optind]);
  891.       GSsetHost(RootGophers[1], "");  /** Nuke the 2nd alternative host **/
  892.       GSsetPort(RootGophers[1], 0);
  893.       numhosts = 1;
  894.       optind++;
  895.      }
  896.      if (optind < argc) {
  897.       GSsetPort(RootGophers[0], atoi(argv[optind]));
  898.       optind++;
  899.      }
  900.  
  901.      /*** Get host #2 from the command line... ***/
  902.      if (optind < argc) {
  903.       GSsetHost(RootGophers[1], argv[optind]);
  904.       numhosts = 2;
  905.       optind++;
  906.      }
  907.      if (optind < argc) {
  908.       GSsetPort(RootGophers[1], atoi(argv[optind]));
  909.       optind++;
  910.      }
  911.  
  912.      /*** If the title hasn't been set, then add a default title **/
  913.      if (GSgetTitle(RootGophers[0]) == NULL) {
  914.       sprintf(sTmp, "Root gopher server: %s", GSgetHost(RootGophers[0]));
  915.       GSsetTitle(RootGophers[0], sTmp);
  916.       sprintf(sTmp, "Root gopher server: %s", GSgetHost(RootGophers[1]));
  917.       GSsetTitle(RootGophers[1], sTmp);
  918.      }
  919.  
  920.      /*** Set up global variables, etc. ***/
  921.  
  922.      Initialize();
  923.  
  924.      if (Bkmarksfirst) {
  925.       CurrentDir = BookmarkDir;
  926.       
  927.       if (CurrentDir != NULL)
  928.            GDaddGS(CurrentDir, RootGophers[0]);
  929.      } else {
  930.       int rnum;
  931.  
  932.       srand(time(NULL));
  933.       rnum = rand() % numhosts;
  934.       process_request(RootGophers[rnum]);
  935.  
  936.           /* just process the command line entry */
  937.           if( GSgetType(RootGophers[0]) != A_DIRECTORY ) {
  938.            refresh();
  939.            CURexit(CursesScreen);
  940.            exit(0);
  941.           }
  942.      }
  943.  
  944.      if (CurrentDir == NULL || GDgetNumitems(CurrentDir) <= 0) {
  945.       /*
  946.        * We didn't get anything from that gopher server.  Either
  947.        * it is down, doesn't exist, or is empty or otherwise
  948.        * busted.
  949.            *
  950.            * Try any alternative hosts that are available..
  951.        */
  952.  
  953.       while (optind < argc && CurrentDir == NULL) {
  954.            GSsetHost(RootGophers[0], argv[optind]);
  955.            optind++;
  956.            GSsetPort(RootGophers[0], atoi(argv[optind]));
  957.            optind++;
  958.            process_request(RootGophers[0]);
  959.       }
  960.      }      
  961.  
  962.      if (CurrentDir == NULL || GDgetNumitems(CurrentDir) <= 0) {
  963.       CURexit(CursesScreen);
  964.       fprintf(stderr,
  965.           "%s: Nothing received for main menu, can't continue\n", argv[0]);
  966.       exit(1);
  967.      }      
  968.  
  969.      while (bDone == FALSE)
  970.      {
  971.       GetMenu(CurrentDir, &TypedChar, Garbled);
  972.  
  973.       Garbled = TRUE;
  974.  
  975.       switch(TypedChar)
  976.       {
  977.       case '\r':
  978.       case '\n':
  979.            /*** Select the designated item ***/
  980.            if (process_request(GDgetEntry(CurrentDir,GDgetCurrentItem(CurrentDir)-1))==1)
  981.             ;  /** Don't do anything if we failed, I guess **/
  982.            break;
  983.            
  984.       case '\014': /* ^L */
  985. #ifdef VMS
  986.       case '\022': /* ^R */
  987.       case '\027': /* ^W */
  988. #endif
  989.            /*** Redraw the screen ***/
  990.            break;
  991.  
  992.       case '\0':
  993.            /*** What the heck? ***/
  994.            CursesErrorMsg("Strange Error occurred!");
  995.            break;
  996.            
  997.       case 'u':
  998.       case 'U': 
  999.       {
  1000.            GopherDirObj *tempGdir;
  1001.  
  1002.            /*** Don't highlight texts which aren't search hits ***/
  1003.            Searchstring = NULL;
  1004.  
  1005.            /*** Go up a directory level ***/
  1006.            tempGdir = CurrentDir;
  1007.            /** Don't destroy root level directory, or bookmarks **/
  1008.            if (popgopher(&CurrentDir)==0 && tempGdir != CurrentDir) {
  1009.             if (tempGdir != BookmarkDir)
  1010.              GDdestroy(tempGdir);
  1011.            }
  1012.       }
  1013.            break;
  1014.  
  1015.       case 's':  /*** Save a file directly ***/
  1016.            if (SecureMode == TRUE) {
  1017.             CursesErrorMsg("Sorry, can't save files in securemode");
  1018.             break;
  1019.            }
  1020.            Save_file(GDgetEntry(CurrentDir,GDgetCurrentItem(CurrentDir)-1), NULL,NULL);
  1021.            break;
  1022.            
  1023.       case 'D':
  1024.            Download_file(GDgetEntry(CurrentDir,GDgetCurrentItem(CurrentDir)-1));
  1025.            break;
  1026.  
  1027.       case 'v':  /** View bookmark list **/
  1028.       {
  1029.            if (BookmarkDir == NULL) {
  1030.             CursesErrorMsg("No bookmarks are defined");
  1031.             break;
  1032.            }
  1033.  
  1034.            /** Don't push an empty gopher directory... **/
  1035.            if (CurrentDir != NULL)
  1036.             pushgopher(CurrentDir); 
  1037.            
  1038.            CurrentDir = BookmarkDir;
  1039.  
  1040.            break;
  1041.       }           
  1042.  
  1043.       case 'a': /** add current item as a bookmark **/
  1044.       {
  1045.            GopherObj *tmpgs;
  1046.            char newtitle[256];
  1047.            
  1048.            if (BookmarkDir == NULL) {
  1049.              BookmarkDir = GDnew(32);
  1050.             GDsetTitle(BookmarkDir, "Bookmarks");
  1051.            }
  1052.  
  1053.            tmpgs = GSnew();
  1054.            GScpy(tmpgs, GDgetEntry(CurrentDir, GDgetCurrentItem(CurrentDir)-1));
  1055.            
  1056.            strcpy(newtitle, GSgetTitle(tmpgs));
  1057.            if (CURGetOneOption(CursesScreen, "Name for this bookmark? ", newtitle) <0)
  1058.             break;
  1059.            if (*newtitle == '\0')
  1060.             break;
  1061.  
  1062.            GSsetTitle(tmpgs, newtitle);
  1063.            GDaddGS(BookmarkDir, tmpgs);
  1064.            GSdestroy(tmpgs);
  1065.  
  1066.            ChangedDefs = TRUE;
  1067.  
  1068.            break;
  1069.       }
  1070.  
  1071.       case 'A': /*** Add current directory/search as a bookmark **/
  1072.       {
  1073.            GopherObj *tmpgs;
  1074.            char newtitle[256];
  1075.  
  1076.            if (BookmarkDir == NULL) {
  1077.             BookmarkDir = GDnew(32);
  1078.             GDsetTitle(BookmarkDir, "Bookmarks");
  1079.            }
  1080.  
  1081.            if (CurrentDir == BookmarkDir) {
  1082.             CursesErrorMsg("Sorry, can't make a bookmark of bookmarks");
  1083.             break;
  1084.            }
  1085.            
  1086.            tmpgs = GSnew();
  1087.            if (iLevel == 0)
  1088.             GScpy(tmpgs, RootGophers[0]);
  1089.            else
  1090.             GScpy(tmpgs, GDgetEntry(OldDirs[iLevel-1], GDgetCurrentItem(OldDirs[iLevel-1])));
  1091.            
  1092.            strcpy(newtitle, GDgetTitle(CurrentDir));
  1093.            if (CURGetOneOption(CursesScreen, "Name for this bookmark? ", newtitle)<0)
  1094.             break;
  1095.            if (*newtitle == '\0')
  1096.             break;
  1097.  
  1098.            GSsetTitle(tmpgs, newtitle);
  1099.  
  1100.            /*** Freeze the search, if there was one. ***/
  1101.            if (GSgetType(tmpgs) == '7') {
  1102.             char ickypath[512];
  1103.             strcpy(ickypath, GSgetPath(tmpgs));
  1104.             strcat(ickypath, "\t");
  1105.             strcat(ickypath, Searchstring);
  1106.             GSsetPath(tmpgs, ickypath);
  1107.             GSsetType(tmpgs, '1');
  1108.            }
  1109.  
  1110.            GDaddGS(BookmarkDir, tmpgs);
  1111.  
  1112.            ChangedDefs = TRUE;
  1113.  
  1114.            break;
  1115.       }
  1116.  
  1117.       case 'd':  /*** Delete a bookmark ***/
  1118.       {
  1119.            GopherDirObj *tempgd;
  1120.            int i;
  1121.  
  1122.  
  1123.            if (GDgetNumitems(CurrentDir) == 1) {
  1124.             /** Last item in the directory
  1125.                 Pop up a directory **/
  1126.             tempgd = CurrentDir;
  1127.             /** Don't destroy root level directory, or bookmarks **/
  1128.             if (popgopher(&CurrentDir)==0 && tempgd != CurrentDir) {
  1129.              if (tempgd != BookmarkDir)
  1130.                   GDdestroy(tempgd);
  1131.             } else {
  1132.              CursesErrorMsg("Sorry, can't delete top level directory.");
  1133.              scline(-1, 1, CurrentDir);
  1134.             }
  1135.             ChangedDefs = TRUE;
  1136.            }
  1137.  
  1138.  
  1139.            tempgd = GDnew(GDgetNumitems(CurrentDir)+1);
  1140.  
  1141.            for (i=0; i<GDgetNumitems(CurrentDir); i++) {
  1142.             if (i != (GDgetCurrentItem(CurrentDir) - 1))
  1143.              GDaddGS(tempgd, GDgetEntry(CurrentDir, i));
  1144.            }
  1145.            GDsetTitle(tempgd, GDgetTitle(CurrentDir));
  1146.            GDsetCurrentItem(tempgd, GDgetCurrentItem(CurrentDir));
  1147.  
  1148.            if (GDgetCurrentItem(CurrentDir) == GDgetNumitems(CurrentDir))
  1149.             GDsetCurrentItem(tempgd, (GDgetCurrentItem(CurrentDir)-1));
  1150.  
  1151.            GDdestroy(CurrentDir);
  1152.  
  1153.            if (CurrentDir == BookmarkDir)
  1154.             BookmarkDir = tempgd;
  1155.            
  1156.            CurrentDir = tempgd;
  1157.            
  1158.            ChangedDefs = TRUE;
  1159.  
  1160.            break;
  1161.       }
  1162.  
  1163.       case 'M':
  1164.       case 'm': 
  1165.       {
  1166.            GopherDirObj *tempGdir = NULL;
  1167.            
  1168.            while (popgopher(&CurrentDir) != -1) {
  1169.             if (tempGdir != NULL)
  1170.              GDdestroy(tempGdir);
  1171.             tempGdir = CurrentDir;
  1172.            }
  1173.  
  1174.       }
  1175.  
  1176.            break;
  1177.  
  1178. #ifdef VMS
  1179.       /*
  1180.        * I can't get ^C and ^Y working with PASTHRU on VMS,
  1181.        * so we'll just fake it here.
  1182.        */
  1183.       case 3:
  1184.       case 25:
  1185. #endif
  1186.       case 'q':
  1187.            /*** Quit the program ***/
  1188.            if (TRUE == ReallyQuit()) {
  1189.             bDone = TRUE;
  1190.             CURexit(CursesScreen);
  1191.             break;
  1192.            }
  1193.  
  1194.            break;
  1195.  
  1196.       case 'Q':
  1197.            /*** Quit the program, don't ask ***/
  1198.            bDone = TRUE;
  1199.            CURexit(CursesScreen);
  1200.            break;
  1201.            
  1202.       case 'O':
  1203.            /*** Change various program things ***/
  1204.            SetOptions();
  1205.            break;
  1206.               
  1207.       case '=':
  1208.            describe_gopher("Gopher Item Information", 
  1209.                    GDgetEntry(CurrentDir, GDgetCurrentItem(CurrentDir)-1));
  1210.            break;
  1211.  
  1212.       case '^':
  1213.       {
  1214.            if (iLevel == 0)
  1215.             describe_gopher("Gopher Directory Information",
  1216.                     RootGophers[0]);
  1217.            else
  1218.             describe_gopher("Gopher Directory Information",
  1219.                     GDgetEntry(OldDirs[iLevel-1],
  1220.                            GDgetCurrentItem(OldDirs[iLevel-1])-1));
  1221.            break;
  1222.       }
  1223.                    
  1224.  
  1225.       case '?':
  1226.       {
  1227.            /*** Display help file ***/
  1228.            GopherObj *tmpgs;
  1229.  
  1230.            tmpgs = GSnew();
  1231.            GSsetTitle(tmpgs, "Gopher Help File");
  1232.            
  1233.            CURexit(CursesScreen);
  1234.            display_file(GOPHERHELP, tmpgs);
  1235.            CURenter(CursesScreen);
  1236.            GSdestroy(tmpgs);
  1237.            break;
  1238.       }
  1239.  
  1240.       default :
  1241.            CURBeep(CursesScreen);
  1242.            Garbled = FALSE;
  1243.            break;
  1244.  
  1245.       }
  1246.      }
  1247.      if (ChangedDefs)
  1248.       write_rc();
  1249.  
  1250.      GDdestroy(CurrentDir);
  1251.      exit(0);
  1252.      
  1253.      return(0);
  1254. }     
  1255.  
  1256.  
  1257. int
  1258. Load_Index(ZeGopher)
  1259.   GopherStruct *ZeGopher;
  1260. {
  1261.      Draw_Status("Searching Text...");
  1262.      refresh();
  1263.  
  1264.      return(Load_Index_or_Dir(ZeGopher, Searchstring));
  1265. }
  1266.  
  1267. int
  1268. Load_Dir(ZeGopher)
  1269.   GopherStruct *ZeGopher;
  1270. {
  1271.      Searchstring= NULL;
  1272.      return(Load_Index_or_Dir(ZeGopher, NULL));
  1273. }
  1274.  
  1275.  
  1276. int
  1277. twirl()
  1278. {
  1279.      static int twirlnum = 0;
  1280.      static char *twirls = "-/|\\";
  1281.  
  1282.      addch('\b');
  1283.      addch(*(twirls + (twirlnum++ % 4 )));
  1284.      refresh();
  1285.  
  1286.      return(0);
  1287. }
  1288.  
  1289. int
  1290. Load_Index_or_Dir(ZeGopher, Searchmungestr)
  1291.   GopherStruct *ZeGopher;
  1292.   char *Searchmungestr;
  1293. {
  1294.      int failed = 0;
  1295.      int sockfd;
  1296.      int i;
  1297.      char sTmp[10];
  1298.      static char DirTitle[512];
  1299.      GopherDirObj *NewDir = NULL;
  1300.  
  1301.      NewDir = GDnew(32);
  1302.  
  1303.      sTmp[0]= '\0';
  1304.  
  1305.      Draw_Status("Connecting..."); refresh();
  1306.  
  1307.      if ((sockfd = GSconnect(ZeGopher)) <0) {
  1308.       check_sock(sockfd, GSgetHost(ZeGopher), GSgetPort(ZeGopher));
  1309.       failed = 1;
  1310.      }
  1311.      else {
  1312.       if (GSgetType(ZeGopher) == A_DIRECTORY) {
  1313.            Draw_Status("Retrieving Directory..."); refresh();
  1314.            writestring(sockfd, GSgetPath(ZeGopher));
  1315.            writestring(sockfd, "\r\n");
  1316.       }
  1317.       else if (GSgetType(ZeGopher) == A_INDEX) {
  1318.            Draw_Status("Searching..."); refresh();
  1319.            writestring(sockfd, GSgetPath(ZeGopher));
  1320.            writestring(sockfd, "\t");
  1321.            writestring(sockfd, Searchmungestr);
  1322.            writestring(sockfd, "\r\n");
  1323.       }
  1324.  
  1325.       i = GDfromNet(NewDir, sockfd, twirl);
  1326.  
  1327.       if (i <= 0) {
  1328.            CursesErrorMsg("Nothing available.");
  1329.            failed = 1;
  1330.            return(failed);
  1331.       }
  1332.  
  1333.       if (GSgetType(ZeGopher) == A_INDEX) {
  1334.            sprintf(DirTitle, "%s: %s", GSgetTitle(ZeGopher), Searchmungestr);
  1335.            GDsetTitle(NewDir, DirTitle);
  1336.       }
  1337.           else
  1338.            GDsetTitle(NewDir, GSgetTitle(ZeGopher));
  1339.  
  1340.       /** Don't push an empty gopher directory... **/
  1341.       if (CurrentDir != NULL)
  1342.            pushgopher(CurrentDir); 
  1343.  
  1344.       CurrentDir = NewDir;
  1345.       
  1346.      }
  1347.      i = closenet(sockfd);
  1348.      return(failed);
  1349. }
  1350.  
  1351.  
  1352.  
  1353. int
  1354. process_request(ZeGopher)
  1355.   GopherStruct *ZeGopher;
  1356. {
  1357.      int failed=0;
  1358.  
  1359.      switch(GSgetType(ZeGopher)) {
  1360.      case -1:
  1361.       break;
  1362.  
  1363.      case A_FILE:
  1364.       Draw_Status("Receiving Information...");
  1365.       refresh();
  1366.       showfile(ZeGopher);
  1367.       break;
  1368.  
  1369.      case A_GIF:
  1370.      case A_IMAGE:
  1371.      case A_MIME:
  1372.       if (!SecureMode) {
  1373.            Draw_Status("Receiving Information...");
  1374.            refresh();
  1375.            showfile(ZeGopher);
  1376.       }
  1377.       else
  1378.            CursesErrorMsg("Sorry Cannot display this file anonymously");
  1379.       break;
  1380.  
  1381.      case A_MACHEX:
  1382.      case A_PCBIN:
  1383.      case A_UNIXBIN:
  1384.       if (!SecureMode)
  1385.            Save_file(ZeGopher, NULL, NULL);
  1386.       else
  1387.            CursesErrorMsg("Sorry, cannot transfer files in securemode");
  1388.       break;
  1389.       
  1390.      case A_DIRECTORY:
  1391.       Draw_Status("Receiving Directory...");
  1392.       refresh();
  1393.       failed = Load_Dir(ZeGopher);
  1394.       break;
  1395.             
  1396.      case A_TELNET:
  1397.      case A_TN3270:
  1398.       do_tel_3270(ZeGopher);
  1399.       break;
  1400.  
  1401.      case A_INDEX:
  1402.       refresh();
  1403.       Searchstring = do_index(ZeGopher);
  1404.       Draw_Status("Searching Text...");
  1405.       if (Searchstring != NULL)
  1406.            failed=Load_Index(ZeGopher);
  1407.       else
  1408.            failed = 1;
  1409.       break;
  1410.       
  1411.      case A_CSO:
  1412.       do_cso(ZeGopher);
  1413.       break;
  1414.  
  1415.      case A_SOUND:
  1416.       Draw_Status("Receiving Sound...");
  1417.       refresh();
  1418.       do_sound(ZeGopher);
  1419.       break;
  1420.  
  1421.      case A_HTML:
  1422.       Draw_Status("Receiving HTML page...");
  1423.       refresh();
  1424.       do_html(ZeGopher);
  1425.       break;
  1426.      }
  1427.      return(failed);
  1428. }
  1429.  
  1430.  
  1431. void
  1432. describe_gopher(banner, ZeGopher)
  1433.   char *banner;
  1434.   GopherStruct *ZeGopher;
  1435. {
  1436.      char *tmpfilename;
  1437.      FILE *tmpfile;
  1438.  
  1439.      CURexit(CursesScreen);    /* do this *before* possible exit() below */
  1440.  
  1441.      Gopenfile = tmpfilename = tempnam("/tmp/moo", "gopher");
  1442.  
  1443.      if ((tmpfile = fopen(tmpfilename, "w")) == NULL)
  1444.        fprintf(stderr, "Couldn't make a tmp file!\n"), exit(-1);
  1445.  
  1446.      fprintf(tmpfile,"Name=%s\nType=%c\nPort=%d\nPath=%s\nHost=%s\n\n",
  1447.          GSgetTitle(ZeGopher),
  1448.          GSgetType(ZeGopher),
  1449.          GSgetPort(ZeGopher),
  1450.          GSgetPath(ZeGopher),
  1451.          GSgetHost(ZeGopher));
  1452.  
  1453.      fclose(tmpfile);
  1454.  
  1455.      display_file(tmpfilename, ZeGopher);
  1456.      if (unlink(tmpfilename) != 0)
  1457.       fprintf(stderr, "Couldn't unlink!!!\n"), exit(-1);
  1458.      
  1459.      Gopenfile = NULL;
  1460.      free(tmpfilename);
  1461.  
  1462.      CURenter(CursesScreen); /* do this after unlink fails */
  1463.  
  1464.      return;
  1465. }
  1466.